﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CPPEI.Win32
{
    public class WindowsScreen
    {
        Bitmap btm;
        Graphics g;
        private byte[] lastBuffer;
        private byte[] currentBuffer;

        public WindowsScreen(int width, int height)
        {
            btm = new Bitmap(width, height);
            g = Graphics.FromImage(btm);
        }

        /// <summary>
        /// 捕获指定的屏幕图像
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public byte[] Capture(int x, int y, int width, int height)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            g.CopyFromScreen(x, y, 0, 0, new Size(width, height));
            stopwatch.Stop();
            Debug.WriteLine("copyscreen:{0}ms", stopwatch.ElapsedMilliseconds);
            currentBuffer = GetBuffer(btm);

            if (lastBuffer != null)
            {
                byte[] returnBuffer = new byte[currentBuffer.Length];
                byte[] temp = lastBuffer;
                for (int index = 0; index < currentBuffer.Length; index++)
                {
                    returnBuffer[index] = (byte)((currentBuffer[index] ^ lastBuffer[index]));
                    if (returnBuffer[index] != 0)
                    {
                        returnBuffer[index] = currentBuffer[index];
                    }
                }
                lastBuffer = currentBuffer;
                return returnBuffer;
            }
            else
            {
                lastBuffer = currentBuffer;
            }
            return currentBuffer;

            //return GZip.Compress(GetBuffer(btm));
        }


        public static byte[] GetBuffer(Bitmap srcBitmap)
        {
            int wide = srcBitmap.Width;
            int height = srcBitmap.Height;
            Rectangle rect = new Rectangle(0, 0, wide, height);
            //将Bitmap锁定到系统内存中,获得BitmapData
            //BitmapData srcBmData = srcBitmap.LockBits(rect,
            //          ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            BitmapData srcBmData = srcBitmap.LockBits(rect,
                      ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);
            //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
            System.IntPtr srcPtr = srcBmData.Scan0;
            //将Bitmap对象的信息存放到byte数组中
            int src_bytes = srcBmData.Stride * height;
            byte[] srcValues = new byte[src_bytes];
            //复制GRB信息到byte数组
            System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes);
            srcBitmap.UnlockBits(srcBmData);
            return srcValues;
        } 

        /// <summary>
        /// 列举所有屏幕信息
        /// </summary>
        /// <returns></returns>
        public static List<ScreenInfo> EnumerateScreens()
        {
            Screen[] screens = Screen.AllScreens;
            List<ScreenInfo> screenInfos = new List<ScreenInfo>();
            foreach (Screen screen in screens)
            {
                ScreenInfo screenInfo = new ScreenInfo();
                screenInfo.X = screen.WorkingArea.X;
                screenInfo.Y = screen.WorkingArea.Y;
                screenInfo.Width = screen.WorkingArea.Width;
                screenInfo.Height = screen.WorkingArea.Height;

                screenInfos.Add(screenInfo);
            }
            return screenInfos;
        }
    }

    /// <summary>
    /// 压缩数据
    /// </summary>
    public class GZip
    {
        /// <summary>
        /// 将字节数组进行压缩后返回压缩的字节数组
        /// </summary>
        /// <param name="data">需要压缩的数组</param>
        /// <returns>压缩后的数组</returns>
        public static byte[] Compress(byte[] data)
        {
            MemoryStream stream = new MemoryStream();
            GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress);
            gZipStream.Write(data, 0, data.Length);
            gZipStream.Close();
            return stream.ToArray();
        }

        /// <summary>
        /// 解压字符数组
        /// </summary>
        /// <param name="data">压缩的数组</param>
        /// <returns>解压后的数组</returns>
        public static byte[] Decompress(byte[] data)
        {
            MemoryStream stream = new MemoryStream();

            GZipStream gZipStream = new GZipStream(new MemoryStream(data), CompressionMode.Decompress);

            byte[] bytes = new byte[40960];
            int n;
            while ((n = gZipStream.Read(bytes, 0, bytes.Length)) != 0)
            {
                stream.Write(bytes, 0, n);
            }
            gZipStream.Close();
            return stream.ToArray();
        }
    }
}
